
#include "Queue.h"

C_Queue_Ptr
C_Queue_New(C_Mem_Free_t f)
{
	C_Queue_Ptr p = C_Malloc(sizeof(C_Queue));
	C_Queue_Init(p, f);
	return p;
}

void
C_Queue_Init(C_Queue_Ptr p, C_Mem_Free_t f)
{
	if (p == NULL)
		return;

	p->Mutex = C_Mutex_New();
	p->CondVar = C_CondVar_New();
	p->List = C_List_New();

	if (p->Mutex == NULL || p->CondVar == NULL || p->List == NULL)
	{
		C_Mutex_Free(p->Mutex);
		C_CondVar_Free(p->CondVar);
		C_List_Free(p->List);
	}

	C_List_Set_Mem_Free(p->List, f);
}

void
C_Queue_Free(C_Queue_Ptr p)
{
	if (p == NULL)
		return;

	if (p->Mutex != NULL)
	{
		C_Mutex_Free(p->Mutex);
	}

	if (p->CondVar != NULL)
	{
		C_CondVar_Free(p->CondVar);
	}

	if (p->List != NULL)
	{
		C_List_Free(p->List);
	}

	C_Free(p);
}

C_Error_t
C_Queue_Put(C_Queue_Ptr p, void *data)
{
	C_Error_t err;

	if (p == NULL)
		return C_ERR_INVALID_PARAMS;

	C_Mutex_Aquire(p->Mutex);

	err = C_List_Insert(p->List, data, NULL);

	C_Mutex_Release(p->Mutex);

	C_CondVar_Signal(p->CondVar);

	return err;
}

C_Error_t
C_Queue_Get(C_Queue_Ptr p, void **data)
{
	if (p == NULL || data == NULL)
		return C_ERR_INVALID_PARAMS;

	C_Mutex_Aquire(p->Mutex);

	while (p->List->Size == 0)
	{
		C_CondVar_Wait(p->CondVar, p->Mutex);
	}

	C_List_Remove(p->List, p->List->Head, data);

	C_Mutex_Release(p->Mutex);

	return C_ERR_NOERR;
}

C_Error_t
C_Queue_Timed_Get(C_Queue_Ptr p, const struct timespec *ts, void **data)
{
	C_Bool_t timedout;
	C_Error_t ret;

	if (p == NULL || ts == NULL || data == NULL)
		return C_ERR_INVALID_PARAMS;

	ret = C_ERR_NOERR;
	*data = NULL;

	C_Mutex_Aquire(p->Mutex);

	while (p->List->Size == 0)
	{
		C_CondVar_TimedWait(p->CondVar, p->Mutex, ts, &timedout);

		if (timedout)
		{
			ret = C_ERR_TIMEOUT;
			break;
		}
	}

	if (ret != C_ERR_TIMEOUT)
	{
		C_List_Remove(p->List, p->List->Head, data);
	}

	C_Mutex_Release(p->Mutex);

	return ret;
}
